import copy
from datetime import datetime,date
from PySide6.QtCore import Qt, QAbstractTableModel, QModelIndex
from PySide6.QtWidgets import QTableView, QMenu, QInputDialog, QErrorMessage, QDialog, QDialogButtonBox, QVBoxLayout
from PySide6 import QtWidgets
from CheckBoxDelegateQt import CheckBoxDelegateQt
from FloatEditDelegateQt import FloatEditDelegateQt
from DateTimeEditDelegateQt import DateTimeEditDelegateQt
from ComboBoxDelegateQt import ComboBoxDelegateQt
from PushButtonDelegateQt import PushButtonDelegateQt
from FileDialogDelegateQt import FileDialogDelegateQt
import traceback
import ui_contacts_new
import sqlalchemy
import sys
from PySide6 import QtCore,QtGui
from PySide6.QtCore import QTimer,QEventLoop,Signal
import mydb
import config_json
# class EmittingStr(QtCore.QObject):
#     textWritten = QtCore.Signal(str)  # 定义一个str的信号
#     def write(self, text):
#             self.textWritten.emit(str(text))
#             # loop = QEventLoop()
#             # QTimer.singleShot(1000, loop.quit)
#             # loop.exec_()


def getAttrRecursive(obj, attr):
    """ Recursive introspection (i.e. get the member 'b' of a member 'a' by name as 'a.b').
    """
    # try:
    #     p = attr.index(".")
    #     obj = getattr(obj, attr[0:p])
    #     return getAttrRecursive(obj, attr[p+1:])
    # except ValueError:
    return getattr(obj, attr)


def setAttrRecursive(obj, attr, value):
    """ Recursive introspection (i.e. set the member 'b' of a member 'a' by name as 'a.b').
    """
    # try:
    #     p = attr.index(".")
    #     obj = getattr(obj, attr[0:p])
    #     setAttrRecursive(obj, attr[p+1:], value)
    # except ValueError:
    setattr(obj, attr, value)


class ObjectListTableModelQt(QAbstractTableModel):
    """ Qt model interface for specified attributes from a dynamic list of arbitrary objects.

    All objects in the list should be of the same type.
    Default is objects are rows and properties are columns.

    Displayed properties are specified as a list of dicts whose keys may include:
    'attr': Name of an object attribute. If specified, data() and setData() will get/set the attribute's value
        for the associated object.
        - May be a path to a child attribute such as "path.to.a.child.attr".
    'header': Text to display in the table's property header.
    'dtype': Attribute type. If not specified, this is inferred either from the templateObject or an object in the list.
    'mode': "Read/Write" or "Read Only". If not specified, defaults to "Read/Write".
    'choices': List of values or (key, value) tuples. If specified, the values (or their keys if they exist) are presented in a combo box.
    'action': Name of a special action associated with this cell. Actions include:
        "button": Clicking on the cell is treated as a button press.
            - setData() calls the object's method specified by the property's 'attr' key.
        "fileDialog": Double clicking on the cell pops up a file dialog.
            - setData() sets the property's 'attr' value to the "path/to/filename" returned form the dialog.
            - If you want some file loading script to run each time the file name is set, set 'attr' to the object
              @property.setter that set's the file name and runs the script.
    'text': String used by certain properties. For example, used to specify a datetime's format or a button's text.

    By specifying each object property (or action) displayed in the model/view as a dict,
    it is easy to simply add new key:value pairs for new custom delegates, and extend the model/view
    code to check for these properties. Furthermore, specifying properties in this way makes for
    easily readable code when adding properties to a model/view. For example:
        properties = [
            {'attr': "name",        'header': "Person", 'isReadOnly': True},  # Read only column of object.name strings.
            {'attr': "age",         'header': "Age"                       },  # Read/Write column of object.age integers.
            {'attr': "birthday",    'header': "D.O.B.", 'text': "%x"      },  # Read/Write column of object.birthday datetimes (format="%x").
            {'attr': "friend.name", 'header': "Friend"                    }]  # Read/Write column of object.friend.name strings.

    :param objects (list): List of objects.
    :param properties (list): List of property dicts {'attr'=str, 'header'=str, 'isReadOnly'=bool, 'choices'=[], ...}
    :param isRowObjects (bool): If True, objects are rows and properties are columns, otherwise vice-versa.
    :param isDynamic (bool): If True, objects can be inserted/deleted, otherwise not.
    :param templateObject (object): Object that will be deep copied to create new objects when inserting into the list.
    """
    def __init__(self, objects=None, properties=None, isRowObjects=True, isDynamic=True, templateObject=None, parent=None):
        QAbstractTableModel.__init__(self, parent)
        self.objects = objects if (objects is not None) else []
        self.properties = properties if (properties is not None) else []
        self.isRowObjects = True
        self.isDynamic = isDynamic
        self.templateObject = templateObject

    def getObject(self, index):
        if not index.isValid():
            return None
        objectIndex = index.row() if self.isRowObjects else index.column()
        try:
            return self.objects[objectIndex]
        except IndexError:
            return None

    def getProperty(self, index):
        if not index.isValid():
            return None
        propertyIndex = index.column() if self.isRowObjects else index.row()
        try:
            return self.properties[propertyIndex]
        except IndexError:
            return None

    def rowCount(self, parent=None, *args, **kwargs):
        return len(self.objects) if self.isRowObjects else len(self.properties)

    def columnCount(self, parent=None, *args, **kwargs):
        return len(self.properties) if self.isRowObjects else len(self.objects)

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        obj = self.getObject(index)
        prop = self.getProperty(index)
        if (obj is None) or (prop is None):
            return None
        try:
            if role in [Qt.DisplayRole, Qt.EditRole]:
                return getAttrRecursive(obj, prop['attr'])
        except:
            traceback.print_exc()
            return None
        return None

    def setData(self, index, value, role=Qt.EditRole):
        if not index.isValid():
            return False
        obj = self.getObject(index)
        prop = self.getProperty(index)
        if (obj is None) or (prop is None):
            return None
        try:
            action = prop.get('action', None)
            if action is not None:
                if action == "button":
                    getAttrRecursive(obj, prop['attr'])()  # Call obj.attr()
                    return True
                elif action == "fileDialog":
                    pass  # File loading handled via @property.setter obj.attr below. Otherwise just sets the file name text.
            if role == Qt.EditRole:
                print(type(value))
                attr=getattr(obj,prop['attr'])
                print(attr,value)
                if attr!=value:
                    setAttrRecursive(obj, prop['attr'], value)
                    try:
                        backend.session.commit()
                        return True
                    except TypeError:
                        traceback.print_exc()
                        backend.session.rollback()
                        return False
                    except sqlalchemy.exc.PendingRollbackError as e:
                        traceback.print_exc()
                        backend.session.rollback()
                        return False
                    except sqlalchemy.exc.StatementError:
                        traceback.print_exc()
                        backend.session.rollback()
                        return False
                    except :
                        traceback.print_exc()
                        return False
                return False
            return False
        except:
            traceback.print_exc()
            return False
        return False

    def flags(self, index):
        flags = QAbstractTableModel.flags(self, index)
        if not index.isValid():
            return flags
        prop = self.getProperty(index)
        if prop is None:
            return flags
        flags |= Qt.ItemIsEnabled
        flags |= Qt.ItemIsSelectable
        mode = prop.get('mode', "Read/Write")
        if "Write" in mode:
            flags |= Qt.ItemIsEditable
        return flags

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole:
            return None
        if ((orientation == Qt.Horizontal) and self.isRowObjects) or ((orientation == Qt.Vertical) and not self.isRowObjects):
            # Display property headers.
            try:
                return self.properties[section]['header']  # Property header.
            except (IndexError, KeyError):
                return None
        else:
            # Display object indices (1-based).
            return (section + 1) if (0 <= section < len(self.objects)) else None

    def insertObjects(self, obj,i, num=1):
        if ((len(self.objects) == 0) and (self.templateObject is None)) or (num <= 0):
            return False
        i = min([max([0, i]), len(self.objects)])  # Clamp i to within [0, # of objects].
        if self.isRowObjects:
            self.beginInsertRows(QModelIndex(), i, i + num - 1)
        for objectIndex in range(i, i + num):
            self.objects.insert(objectIndex, obj)
        if self.isRowObjects:
            self.endInsertRows()
        return True

    def removeObjects(self, i, num=1):
        if (len(self.objects) == 0) or (num <= 0):
            return False
        i = min([max([0, i]), len(self.objects) - 1])  # Clamp i to a valid object index.
        num = min([num, len(self.objects) - i])  # Clamp num to a valid number of objects.
        if num == len(self.objects):
            # Make sure we have a template for inserting objects later.
            if self.templateObject is None:
                self.templateObject = self.objects[0]
        if self.isRowObjects:
            self.beginRemoveRows(QModelIndex(), i, i + num - 1)
            for o in  self.objects[i:i+num]:
                backend.session.delete(o)
            backend.session.commit()
            del self.objects[i:i+num]
            self.endRemoveRows()
        # else:
        #     self.beginRemoveColumns(QModelIndex(), i, i + num - 1)
        #     del self.objects[i:i+num]
        #     self.endRemoveColumns()
        return True

    def moveObjects(self, indices, moveToIndex):
        if len(self.objects) <= 1:
            return False
        try:
            if type(indices) is not list:
                indices = list(indices)
            for i, idx in enumerate(indices):
                indices[i] = min([max([0, idx]), len(self.objects) - 1])  # Clamp indices to valid object indices.
            moveToIndex = min([max([0, moveToIndex]), len(self.objects) - 1])  # Clamp moveToIndex to a valid object index.
            self.beginResetModel()
            objectsToMove = []
            for i in indices:
                objectsToMove.append(self.objects[i])
            for i in reversed(indices):
                del self.objects[i]
            for i, obj in enumerate(objectsToMove):
                j = moveToIndex + i
                j = min([max([0, j]), len(self.objects)])  # Clamp j to within [0, # of objects].
                self.objects.insert(j, obj)
            self.endResetModel()
            return True
        except:
            traceback.print_exc()
            return False

    def clearObjects(self):
        if len(self.objects):
            if self.templateObject is None:
                self.templateObject = self.objects[0]
            self.beginResetModel()
            del self.objects[:]
            self.endResetModel()
    def setObjects(self,objects):
        # if len(self.objects):
        #     if self.templateObject is None:
        #         self.templateObject = self.objects[0]
        self.beginResetModel()
        self.objects=objects
        self.endResetModel()
    def propertyType(self, propertyIndex):
        try:
            prop = self.properties[propertyIndex]
            if 'dtype' in prop.keys():
                return prop['dtype']
            elif 'attr' in prop.keys():
                if len(self.objects) > 0:
                    return type(getAttrRecursive(self.objects[0], prop['attr']))
        except:
            traceback.print_exc()
            return None
        return None


class ObjectListTableViewQt(QTableView):
    """ Qt view for a ObjectListTableModelQt model.

    Right clicking in the view's row or column headers brings up a context menu for inserting/deleting/moving objects
    in the list (optional), or setting an attribute's value for all objects simultaneously.

    Delegates:
    bool: CheckBoxWithoutLabelDelegateQt() - centered check box (no label)
    float: FloatEditDelegateQt() - allows arbitrary precision and scientific notation
    datetime: DateTimeEditDelegateQt("date format") - datetime displayed according to "date format"
    combobox: ComboBoxDelegateQt([choice values or (key, value) tuples]) - list of choice values (or keys if they exist)
    buttons: PushButtonDelegateQt("button text") - clickable button, model's setData() handles the click
    files: FileDialogDelegateQt() - popup a file dialog, model's setData(pathToFileName) handles the rest
    """
    def __init__(self, model, parent=None):
        QTableView.__init__(self, parent)

        # Custom delegates.
        self._checkBoxDelegate = CheckBoxDelegateQt()
        self._floatEditDelegate = FloatEditDelegateQt()
        self._dateTimeEditDelegates = []  # Each of these can have different formats.
        self._comboBoxDelegates = []  # Each of these can have different choices.
        self._pushButtonDelegates = []  # Each of these can have different text.
        self._fileDialogDelegate = FileDialogDelegateQt()

        # Set the model.
        self.setModel(model)

    def setModel(self, model):
        if type(model) is not ObjectListTableModelQt:
            raise RuntimeError("ObjectListTableViewQt.setModel: Model type MUST be ObjectListTableModelQt.")

        QTableView.setModel(self, model)

        # Clear current delegate lists.
        self._dateTimeEditDelegates = []  # Each of these can have different formats.
        self._comboBoxDelegates = []  # Each of these can have different choices.
        self._pushButtonDelegates = []  # Each of these can have different text.

        # Assign custom delegates.
        for i, prop in enumerate(model.properties):
            dtype = model.propertyType(i)
            print(dtype)
            if 'choices' in prop.keys():
                self._comboBoxDelegates.append(ComboBoxDelegateQt(prop['choices']))
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._comboBoxDelegates[-1])
                else:
                    self.setItemDelegateForRow(i, self._comboBoxDelegates[-1])
            elif prop.get('action', "") == "fileDialog":
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._fileDialogDelegate)
                else:
                    self.setItemDelegateForRow(i, self._fileDialogDelegate)
            elif prop.get('action', "") == "button":
                self._pushButtonDelegates.append(PushButtonDelegateQt(prop.get('text', "")))
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._pushButtonDelegates[-1])
                else:
                    self.setItemDelegateForRow(i, self._pushButtonDelegates[-1])
            elif dtype is bool:
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._checkBoxDelegate)
                else:
                    self.setItemDelegateForRow(i, self._checkBoxDelegate)
            elif dtype is float:
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._floatEditDelegate)
                else:
                    self.setItemDelegateForRow(i, self._floatEditDelegate)
            elif dtype is datetime:
                self._dateTimeEditDelegates.append(DateTimeEditDelegateQt(prop.get('text', '%c')))
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._dateTimeEditDelegates[-1])
                else:
                    self.setItemDelegateForRow(i, self._dateTimeEditDelegates[-1])
            elif dtype is date:
                self._dateTimeEditDelegates.append(DateTimeEditDelegateQt(prop.get('text', '%c')))
                if model.isRowObjects:
                    self.setItemDelegateForColumn(i, self._dateTimeEditDelegates[-1])
                else:
                    self.setItemDelegateForRow(i, self._dateTimeEditDelegates[-1])

        # Context menus for right click in header.
        # Objects header pops up insert/delete objects menu.
        # Properties header pops up properties menu.
        self.horizontalHeader().setContextMenuPolicy(Qt.NoContextMenu)
        self.verticalHeader().setContextMenuPolicy(Qt.NoContextMenu)
        if model.isDynamic:
            self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
            self.verticalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
            if model.isRowObjects:
                self.horizontalHeader().customContextMenuRequested.connect(self.getPropertyHeaderContextMenu)
                self.verticalHeader().customContextMenuRequested.connect(self.getObjectHeaderContextMenu)
            else:
                self.horizontalHeader().customContextMenuRequested.connect(self.getObjectHeaderContextMenu)
                self.verticalHeader().customContextMenuRequested.connect(self.getPropertyHeaderContextMenu)
        else:
            if model.isRowObjects:
                self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
                self.horizontalHeader().customContextMenuRequested.connect(self.getPropertyHeaderContextMenu)
            else:
                self.verticalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
                self.verticalHeader().customContextMenuRequested.connect(self.getPropertyHeaderContextMenu)

        # Resize columns to fit content.
        self.resizeColumnsToContents()

    def getObjectHeaderContextMenu(self, pos):
        pass
        # if self.model().isRowObjects:
        #     menu = QMenu()
        #     rowOrColumn = "Row"
        #     menu.addAction("append", self.)
        #     menu.addAction("Insert " + rowOrColumn + " " + belowOrAfter + " Selected", self.insertObjectAfterSelectedObjects)
        #     menu.addSeparator()
        #     menu.addAction("Insert " + rowOrColumn + "s " + aboveOrBefore + " Selected", self.insertObjectsBeforeSelectedObjects)
        #     menu.addAction("Insert " + rowOrColumn + "s " + belowOrAfter + " Selected", self.insertObjectsAfterSelectedObjects)
        #     menu.addSeparator()
        #     menu.addAction("Move Selected " + rowOrColumn + "s", self.moveSelectedObjects)
        #     menu.addSeparator()
        #     menu.addAction("Delete Selected " + rowOrColumn + "s", self.removeSelectedObjects)
        #     header = self.verticalHeader() if self.model().isRowObjects else self.horizontalHeader()
        #     return menu.exec_(header.viewport().mapToGlobal(pos))

    def getPropertyHeaderContextMenu(self, pos):
        menu = QMenu()
        if len(self.model().objects) > 1:
            rowOrColumn = "Column" if self.model().isRowObjects else "Row"
            menu.addAction("Set All In Selected " + rowOrColumn, self.setPropertyForAllObjects)
        elif (len(self.model().objects) == 0) and (self.model().templateObject is not None):
            rowOrColumn = "Row" if self.model().isRowObjects else "Column"
            menu.addAction("Add Object " + rowOrColumn, self.appendObject)
        else:
            return
        header = self.horizontalHeader() if self.model().isRowObjects else self.verticalHeader()
        return menu.exec_(header.viewport().mapToGlobal(pos))

    def selectedRows(self):
        selectedIndexes = self.selectionModel().selection().indexes()
        rows = set()
        for index in selectedIndexes:
            rows.add(index.row())
        return sorted(list(rows))

    def selectedColumns(self):
        selectedIndexes = self.selectionModel().selection().indexes()
        columns = set()
        for index in selectedIndexes:
            columns.add(index.column())
        return sorted(list(columns))

    def insertObject(self,obj, i):
        self.model().insertObjects(obj,i, 1)

    def appendObject(self,obj):
        self.insertObject(obj,len(self.model().objects))

    def removeObject(self, i):
        self.model().removeObjects(i, 1)

    # def insertObjectBeforeSelectedObjects(self,obj):
    #     if self.model().isRowObjects:
    #         selectedObjectIndices = self.selectedRows() # else self.selectedColumns()
    #         self.model().insertObject(obj,selectedObjectIndices[0], 1)

    # def insertObjectAfterSelectedObjects(self):
    #     selectedObjectIndices = self.selectedRows() if self.model().isRowObjects else self.selectedColumns()
    #     self.model().insertObjects(selectedObjectIndices[-1] + 1, 1)

    # def insertObjectsBeforeSelectedObjects(self):
    #     num, ok = QInputDialog.getInt(self, "Insert", "Number of objects to insert.", 1, 1)
    #     if ok:
    #         selectedObjectIndices = self.selectedRows() if self.model().isRowObjects else self.selectedColumns()
    #         self.model().insertObjects(selectedObjectIndices[0], num)

    # def insertObjectsAfterSelectedObjects(self):
    #     num, ok = QInputDialog.getInt(self, "Insert", "Number of objects to insert.", 1, 1)
    #     if ok:
    #         selectedObjectIndices = self.selectedRows() if self.model().isRowObjects else self.selectedColumns()
    #         self.model().insertObjects(selectedObjectIndices[-1] + 1, num)

    def removeSelectedObjects(self):
        selectedObjectIndices = self.selectedRows() if self.model().isRowObjects else self.selectedColumns()
        for i in reversed(selectedObjectIndices):
            self.model().removeObjects(i, 1)

    # def moveSelectedObjects(self):
    #     moveToIndex, ok = QInputDialog.getInt(self, "Move", "Move to index.", 1, 1, len(self.model().objects))
    #     if ok:
    #         moveToIndex -= 1  # From 1-based to 0-based.
    #         moveToIndex = min([max([0, moveToIndex]), len(self.model().objects)])  # Clamp moveToIndex to a valid object index.
    #         selectedObjectIndices = self.selectedRows() if self.model().isRowObjects else self.selectedColumns()
    #         self.model().moveObjects(selectedObjectIndices, moveToIndex)

    def clearObjects(self):
        self.model().clearObjects()

    def setPropertyForAllObjects(self):
        selectedPropertyIndices = self.selectedColumns() if self.model().isRowObjects else self.selectedRows()
        if len(selectedPropertyIndices) != 1:
            errorDialog = QErrorMessage(self)
            rowOrColumn = "column" if self.model().isRowObjects else "row"
            errorDialog.showMessage("Must select a single property " + rowOrColumn + ".")
            errorDialog.exec_()
            return
        try:
            propertyIndex = selectedPropertyIndices[0]
            dtype = self.model().propertyType(propertyIndex)
            if dtype is None:
                return
            obj = self.model().objects[0]
            prop = self.model().properties[propertyIndex]
            if "Write" not in prop.get('mode', "Read/Write"):
                return
            model = ObjectListTableModelQt([obj], [prop], self.model().isRowObjects, False)
            view = ObjectListTableViewQt(model)
            dialog = QDialog(self)
            buttons = QDialogButtonBox(QDialogButtonBox.Ok)
            buttons.accepted.connect(dialog.accept)
            buttons.rejected.connect(dialog.reject)
            vbox = QVBoxLayout(dialog)
            vbox.addWidget(view)
            vbox.addWidget(buttons)
            dialog.setWindowModality(Qt.WindowModal)
            dialog.exec_()
            for objectIndex, obj in enumerate(self.model().objects):
                row = objectIndex if self.model().isRowObjects else propertyIndex
                col = propertyIndex if self.model().isRowObjects else objectIndex
                index = self.model().index(row, col)
                if objectIndex == 0:
                    value = self.model().data(index)
                else:
                    if prop.get('action', '') == "fileDialog":
                        try:
                            getAttrRecursive(obj, prop['attr'])(value)
                            self.model().dataChanged.emit(index, index)  # Tell model to update cell display.
                        except:
                            self.model().setData(index, value)
                            self.model().dataChanged.emit(index, index)  # Tell model to update cell display.
                    else:
                        self.model().setData(index, value)
                        self.model().dataChanged.emit(index, index)  # Tell model to update cell display.
        except:
            pass
class ContactDlg(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui=ui_contacts_new.Ui_MainWindow()
        self.ui.setupUi(self)
        # sys.stdout = EmittingStr(textWritten=self.outputWritten)
        # sys.stderr = EmittingStr(textWritten=self.outputWritten)            
        self.db=mydb.MyDb()
        objects=self.db.getDataDays(200)
        obj=objects[0]
        print(dir(obj))
        properties = [
    {'attr': "SampleId",  'header': "id",      'mode': "Read Only"},
    {'attr': "SampleName",  'header': "name",      'mode': "Read Only"},
    {'attr': "SampleWeight",  'header': "weight",      'mode': "Read Only"},
    {'attr': "Content10",       'header': "LO",      'mode': "Read Only"},
    {'attr': "Content20",       'header': "HO",      'mode': "Read Only"},
    {'attr': "Content30",       'header': "LN",      'mode': "Read Only"},
    {'attr': "Content40",       'header': "HN",      'mode': "Read Only"},
    {'attr': "Content50",       'header': "LH",      'mode': "Read Only"},
    {'attr': "Content60",       'header': "HH",      'mode': "Read Only"},    
    ]
        self.model = ObjectListTableModelQt(objects, properties, isRowObjects=True, isDynamic=True)
        self.view = ObjectListTableViewQt(self.model)
        # # Show the model/view and run the application.
        self.view.setAttribute(Qt.WA_DeleteOnClose)
        self.vbox=QtWidgets.QVBoxLayout(self.ui.groupBox)
        self.vbox.addWidget(self.view)
        self.ui.pushButton_search.clicked.connect(self.search)
        self.ui.pushButton_next.clicked.connect(self.next)
        self.ui.pushButton_prev.clicked.connect(self.prev)
        self.ui.pushButton_top.clicked.connect(self.top)
    def outputWritten(self, text):
        # self.textEdit.clear()
        cursor = self.ui.textEdit.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(text)
        self.ui.textEdit.setTextCursor(cursor)
        self.ui.textEdit.ensureCursorVisible()        
    def top(self):
        self.start=0
        self.search()
    def prev(self):
        self.start=self.start-self.limit
        if(self.start<0):
            self.start=0
        self.search()
    def next(self):
        self.start=self.start+self.limit
        # if(self.start<0):
        #     self.start=0
        self.search()
    def search(self):
        s=self.ui.lineEdit.text()
        objects=backend.getContacts(s,"")[self.start:self.start+self.limit]
        self.model.setObjects(objects)
        # self.model = ObjectListTableModelQt(objects, properties, isRowObjects=True, isDynamic=True,templateObject=PartsItem())
    def new_object(self):
        return PartsContact()
    def add(self):
    #yonghu = models.CharField(max_length=30,verbose_name="用户单位")#用户单位
    # yiqixinghao=models.CharField(max_length=30,verbose_name="仪器型号")#仪器型号
    # yiqibh=models.CharField(blank=False,unique=True,max_length=30,verbose_name="仪器编号")#仪器编号
    # baoxiang =  models.CharField(max_length=30,verbose_name="包箱")#包箱
    # shenhe =  models.CharField(max_length=30,verbose_name="审核")#审核
    # yujifahuo_date = models.DateField(verbose_name="预计发货时间")#预计发货时间
    # hetongbh=models.CharField(unique=True,max_length=30,verbose_name="合同编号")#合同编号
        i=PartsContact()
        i.yonghu=""
        i.yiqixinghao=""
        i.yiqibh=''        
        i.baoxiang=""
        i.shenhe=""
        i.yujifahuo_date=datetime.now()
        i.hetongbh=""
        # i.name="temp"
        # i.ct=1
        # i.danwei="个"
        backend.session.add(i)
        # backend.session.commit()
        self.view.appendObject(i)
    def delete(self):
        print("delete")
        self.view.removeSelectedObjects()
        pass
def main():
    d=ContactDlg()
    d.resize(1000,800)
    d.exec_()
if __name__ == "__main__":
    import sys
    from PySide6.QtWidgets import QApplication
    config_json.read_setting()
    app = QApplication(sys.argv)
    d=ContactDlg()
    d.resize(1000,800)
    d.show()
    status = app.exec()
    sys.exit(status)
